/**
 * 
 */
package jvs.peer.xmpp;

import java.util.Collection;

import jvs.peer.io.MessageConstant;
import jvs.peer.io.Session;
import jvs.peer.util.Log;

import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ChatManager;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.util.StringUtils;

/**
 * @author qiangli
 * 
 */
public class XmppSession implements Session, PacketListener, RosterListener {
	private static long instance = 0;
	private static String prefix = StringUtils.randomString(5);

	private static synchronized String nextId() {
		return "isession-" + prefix + Long.toString(instance++);
	}

	private Callback cb;
	private Chat chat;
	private XMPPConnection conn;
	private String peer;
	private boolean active;

	public XmppSession(XMPPConnection conn, String peer, Callback cb) {
		this.conn = conn;
		this.peer = peer;
		this.cb = cb;
	}

	public void send(String text) {
		if (active) {
			cb.onError("Peer unavailable");
			return;
		}
		try {
			chat.sendMessage(text);
		} catch (Exception e) {
			e.printStackTrace();
			cb.onError(e.getMessage());
		}
	}

	public void open() throws Exception {
		try {
			ChatManager cm = conn.getChatManager();
			String tid = nextId();
			chat = cm.createChat(peer, tid, null);
			conn.addPacketListener(this, new XmppSessionFilter(
					MessageConstant.response));
			Roster roster = conn.getRoster();
			active = (roster == null ? true : isActive(roster.getPresence(peer)));
			roster.addRosterListener(this);
			if(Log.DEBUG) {
				Log.log(this, "session open: " + chat.getParticipant() + " "
					+ chat.getThreadID() + " active: " + active);
			}
		} catch (Exception e) {
			throw e;
		}
	}

	private boolean isActive(Presence p) {
		try {
			if (p == null) {
				return true; //
			}
			boolean avail = (Presence.Type.available.equals(p
					.getType()));
			return avail;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	public void close() {
		try {
			if (conn != null) {
				conn.removePacketListener(this);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		cb = null;
		chat = null;
		conn = null;
	}

	public void processPacket(Packet packet) {
		Message msg = (Message) packet;
		cb.onMessage(msg.getBody());
	}

	public boolean isActive() {
		return active;
	}

	public void entriesAdded(Collection<String> addresses) {
	}

	public void entriesDeleted(Collection<String> addresses) {
	}

	public void entriesUpdated(Collection<String> addresses) {
	}

	public void presenceChanged(Presence presence) {
		active = isActive(presence);
	}
}
